-- lua table 扩展
-- Author: Colocasia
-- Date: 2019-07-03

local table = table

local function _each(t)
    local index, ptr;
    return function()
        if 'function' == type(ptr) then
            local ret = ptr()
            if ret then 
                return ret;
            end
        end
        index, ptr = next(t, index);
        if 'table' == type(ptr) then
            ptr = _each(ptr);
            local ret = ptr()
            if ret then 
                return ret;
            end
        end
        return ptr;
    end
end
table.each = _each;

local function _copy(source)
    local tab = {} 
    for k, v in pairs(source or {}) do
        if type(v) ~= "table" then
            tab[k] = v
        else
            tab[k] = _copy(v)
        end
    end
    return tab
end
table.copy = _copy

local function _clone(orig)
    local orig_type = type(orig)
    local copy
    if orig_type == 'table' then
        copy = {}
        for orig_key, orig_value in next, orig, nil do
            if not string.find(orig_key, "__") and type(orig_value) ~= "function" then
                copy[_clone(orig_key)] = _clone(orig_value)
            end
        end
        setmetatable(copy, _clone(getmetatable(orig)))
    else
        copy = orig
    end
    return copy
end
table.clone = _clone;

function table.merge(tables, add)
    local first = tables[1]
    if not first then return {} end
    for key, table in ipairs(tables) do
        if key ~= 1 then
            for k, v in pairs(table) do
                if not add or not first[k] then
                    first[k] = _clone(v)
                end
            end
        end
    end
    return first
end

function table.sum(t, func)
    local total = 0
    for k, v in pairs(t) do
        total = total + (func and func(v, k) or 1)
    end
    return total
end

function table.find(t, func)
    for k, v in pairs(t) do
        if func(v, k) then 
            return v 
        end
    end
    return nil
end

function table.foreach(t, func)
    for k, v in pairs(t) do
        func(v, k)
    end
end

function table.map(array, func)
    local new_array = {}
    for i, v in pairs(array) do
        local o = func(v, i)
        if o then
            new_array[i] = o
        end
    end
    return new_array
end

function table.imap(array, func)
    local new_array = {}
    for i, v in ipairs(array) do
        new_array[i] = func(v, i)
    end
    return new_array
end

return table;
